home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource4
/
203_01
/
yam2.c
< prev
next >
Wrap
Text File
|
1979-12-31
|
17KB
|
732 lines
/*
$title ('yam2.c: file transmission protocol handlers')
$date (4 nov 85)
*/
/*
* Ward Christensen Protocol handler for sending and receiving
* ascii and binary files. Modified for choice of checksum or crc.
*/
#include "yam.h"
#define WCEOT (-10)
#ifdef DEFBYTL
long Modtime; /* Unix style mod time for incoming file */
int Filemode; /* Unix style mode for incoming file */
#endif
/****************************************************************************
FUNCTION:
Ward Christensen modem 7 protocol file tranmission handler
CALLING PARAMETERS:
argc:
count of command line arguments.
argp:
pointer to string of command line arguments.
===========================================================================*/
wcsend(argc, argp)
char **argp;
{
int wcs();
#ifdef IBMPC
/* enbable raw mode */
enblcm(FALSE);
#endif
Crcflg=FALSE;
firstsec=TRUE;
if (Batch)
{
printf("Sending in Batch Mode\n");
/* send files, batch mode */
if (expand(wcs, argc, argp)==ERROR)
goto fubar;
/* transmit null path name for end of data */
if (wctxpn("")==ERROR)
goto fubar;
}
/* send file, not batch mode */
else
{
for (; --argc>=0;)
{
/* open file to transmit. open will compute file size */
if (opentx(1,NULL,*argp++)==ERROR)
goto fubar;
/* Ward Christensen transmit */
if (wctx()==ERROR)
goto fubar;
}
}
return OK;
/* error, close files and send CAN to other end */
fubar:
closetx(TRUE);
canit();
return ERROR;
} /* wcsend */
/****************************************************************************
FUNCTION:
Ward Christensen modem 7 protocol file transmission handler, batch
mode.
CALLING PARAMETERS:
f_buf:
pointer to a structure containing information about file
*pathname:
pointer to directory path name
===========================================================================*/
wcs(f_buf,pathname)
struct find_buf *f_buf;
char *pathname;
{
/* open file, open uses f_buf for file size */
if (opentx(2,f_buf,pathname)==ERROR)
return OK; /* skip over inaccessible files */
if (wctxpn(f_buf->pname)== ERROR)
return ERROR;
if (wctx()==ERROR)
return ERROR;
printf("\n");
return OK;
} /* wcs */
/****************************************************************************
FUNCTION:
Ward Christensen modem 7 protocol file reception handler
CALLING PARAMETERS:
argc:
count of command line arguments.
argp:
pointer to string of command line arguments.
===========================================================================*/
wcreceive(argc, argp)
char **argp;
{
int baslen;
#ifdef IBMPC
/* enbable raw mode */
enblcm(FALSE);
#endif
if (Batch)
{
printf("Receiving in Batch Mode\n");
for (;;)
{
/* create the basename of pathname if one was specified */
if (argc > 0)
{
strcpy(Utility.ubuf,*argp);
baslen=strlen(Utility.ubuf);
}
else
baslen = 0;
/* get file name for batch mode */
if (wcrxpn(&Utility.ubuf[baslen])== ERROR)
goto fubar;
if (Utility.ubuf[baslen]==0)
return OK;
#ifdef DEFBYTL
procheader(Utility.ubuf);
#endif
/* receive file */
if (wcrx(Utility.ubuf)==ERROR)
goto fubar;
}
}
else
for (; --argc>=0;)
{
#ifdef DEFBYTL
procheader(0);
#endif
#ifdef XMODEM
printf("Receive:'%s' FILE OPEN\n", *argp);
#endif
if (wcrx(*argp++)==ERROR)
goto fubar;
}
return OK;
fubar:
canit();
closerx(TRUE);
return ERROR;
} /* wcreceive */
/****************************************************************************
FUNCTION:
Fetch a pathname from the other end as a C ctyle ASCII string.
Length is indeterminate as long as less than blklen
a null string represents no more files
CALLING PARAMETERS:
===========================================================================*/
wcrxpn(rpn)
char *rpn; /* receive a pathname */
{
purgeline();
firstsec=TRUE;
#ifdef STATLINE
lpstat("Fetching pathname");
#else
printf("\nFetching pathname ");
#endif
/* slight pause to allow slow systems to get ready */
sleep(5);
totsecs = -1;
if (wcgetsec(rpn, 100, Crcflg?WANTCRC:NAK) != 0)
return ERROR;
sendbyte(ACK);
/* clear line of status message above */
#ifndef STATLINE
printf("\r \r");
#endif
return OK;
} /* wcrxpn */
/****************************************************************************
FUNCTION:
transmit path name for batch mode transmission.
CALLING PARAMETERS:
name:
pointer to file name to transmit.
===========================================================================*/
wctxpn(name)
char *name;
{
char *p;
/*??????*/
totsecs = -1;
#ifdef STATLINE
pstat("Awaiting pathname NAK");
#else
printf("Awaiting pathname NAK ");
#endif
if ((firstch=readbyte(400))==TIMEOUT)
return ERROR;
if (firstch==WANTCRC)
Crcflg=TRUE;
/* don't send drive specification */
if (p=index(':', name))
name = ++p;
/* sector number 0 for pathname */
if (wcputsec(name, 0, SECSIZ)==ERROR)
{
printf("Can't send pathname %s\n", name);
return ERROR;
}
#ifndef STATLINE
printf("\r \r");
#endif
return OK;
} /* wctxpn */
/****************************************************************************
FUNCTION:
Adapted from CMODEM13.C, written by Jack M. Wierda and Roderick W. Hart
CALLING PARAMETERS:
===========================================================================*/
wcrx(name)
char *name;
{
int sendchar, sectnum, sectcurr;
#ifdef DEFBYTL
int cblklen; /* bytes to dump this block */
#endif
if (openrx(name)==ERROR)
return ERROR;
firstsec=TRUE;
totsecs=sectnum=0;
sendchar=Crcflg?WANTCRC:NAK;
for (;;)
{
#ifdef STATLINE
if (!Quiet)
pstat("block %3d %2dk", totsecs, totsecs/8 );
#else
if (!Quiet && !View)
printf("\rblock %3d %2dk ", totsecs, totsecs/8 );
#endif
purgeline();
sectcurr=wcgetsec(Utility.ubuf, (sectnum&0177)?70:130,
sendchar);
if (sectcurr==(sectnum+1 &0xff))
{
sectnum++;
/*
* if the compiler supports longs && the o/s blocks the
* exact length of files then and only then use the file length
* info (if transmitted).
*/
#ifdef DEFBYTL
#ifdef BYTEFLENGTH
wcj = cblklen = Bytesleft>blklen ? blklen:Bytesleft;
#else
wcj = cblklen = blklen;
#endif
#else
wcj = blklen;
#endif
for (cp=Utility.ubuf; --wcj>=0; )
if (fputc(*cp++, fout)==ERROR)
{
printf("\nDisk Full\n");
return ERROR;
}
#ifndef XMODEM
if (View)
{
#ifdef DEFBYTL
wcj = cblklen;
#else
wcj = blklen;
#endif
for (cp=Utility.ubuf;--wcj>=0;)
putchar(*cp++);
}
#endif
#ifdef DEFBYTL
if ((Bytesleft -= cblklen) < 0)
Bytesleft = 0;
#endif
totsecs += blklen/128;
sendchar=ACK;
}
else if (sectcurr==sectnum)
{
wcperr("received dup block\n");
sendchar=ACK;
}
else if (sectcurr==WCEOT)
{
sendbyte(ACK);
/* don't pad the file any more than it already is */
closerx(FALSE);
return OK;
}
else if (sectcurr==ERROR)
return ERROR;
else
{
printf(" Sync Error: got %d\n", sectcurr);
return ERROR;
}
}
} /* wcrx */
/****************************************************************************
FUNCTION:
wcgetsec fetches a Ward Christensen type sector.
Returns sector number encountered or ERROR if valid sector not received,
or CAN CAN received or WCEOT if eot sector.
time is timeout for first char, set to 4 seconds thereafter
*************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
(Caller must do that when he is good and ready to get next sector)
CALLING PARAMETERS:
rxbuf:
pointer to buffer to place received data from modem
time:
sendchar:
===========================================================================*/
wcgetsec(rxbuf, time, sendchar)
char *rxbuf;
int time;
{
int sectcurr;
for (Lastrx=errors=0; errors<RETRYMAX; ++errors, ++toterrs)
{
/* stop on user entered ^C */
if(CIREADY && getcty()==CAN)
return ERROR;
sendbyte(sendchar); /* send it now, we're ready! */
/* ingnore echo */
purgeline();
/* special char for larger block size */
if ((firstch=readbyte(time))==STX)
{
blklen=KSIZE;
goto get2;
}
/* normal wc start char */
if (firstch==SOH)
{
blklen=SECSIZ;
get2:
/* verify sector number sent properly */
sectcurr=readbyte(50);
if ((sectcurr+readbyte(50))==0xff)
{
/* rx block, compute checksum */
oldcrc=checksum=0;
for (cp=rxbuf,wcj=blklen; --wcj>=0; )
{
if ((firstch=readbyte(50)) < 0)
goto bilge;
oldcrc=updcrc(firstch, oldcrc);
checksum += (*cp++ = firstch);
}
/* get first byte of check sum */
if ((firstch=readbyte(50)) < 0)
goto bilge;
/* calc crc if crc mode requested */
if (Crcflg)
{
oldcrc=updcrc(firstch, oldcrc);
if ((firstch=readbyte(50)) < 0)
goto bilge;
oldcrc=updcrc(firstch, oldcrc);
if (oldcrc)
{
wcperr(NULL);
printf("Bad CRC=0%o\n", oldcrc);
}
else
{
firstsec=FALSE;
/* normal return (crc mode) with current block # */
return sectcurr;
}
}
/* not-crc. verify calcualted checksum to actual */
else if (((checksum-firstch)&0xff)==0)
{
firstsec=FALSE;
/* normal return with current block # */
return sectcurr;
}
else
{
wcperr(NULL);
printf("Checksum Bad rx=0%o cx=0%o\n",firstch, checksum);
}
}
else
wcperr("block number garbled\n");
}
/* make sure eot really is eot and not just mixmash */
else if (firstch==EOT && readbyte(2)==TIMEOUT)
return WCEOT;
/* CANcel */
else if (firstch==CAN)
{
if (Lastrx==CAN)
{
wcperr("Sender CANcelled\n");
return ERROR;
}
else
{
Lastrx=CAN;
continue;
}
}
else if (firstch==TIMEOUT)
{
bilge:
wcperr("Timeout\n");
}
/* display modem status register if supported in readbyte */
else if (firstch==ERROR)
{
wcperr(NULL);
printf("Modem SR=0%o\n", Mstatus);
}
else
{
wcperr(NULL);
printf("Got 0%o block header\n", firstch);
}
Lastrx=0;
while (readbyte(2)!=TIMEOUT)
;
if (firstsec)
sendchar = Crcflg?WANTCRC:NAK;
else
{
time=40;
sendchar = NAK;
}
}
/* try to stop the bubble machine. */
canit(); return ERROR;
} /* wcgetsec */
/****************************************************************************
FUNCTION:
print error message to console for block transmission or reception
error.
CALLING PARAMETERS:
*s:
pointers to string to display after error message
===========================================================================*/
wcperr(s)
char *s;
{
/* block number is already displayed in normal mode */
if (View)
printf("block %3d ", totsecs);
printf("errors %d: ", toterrs);
printf(s);
} /* wcperr */
/****************************************************************************
FUNCTION:
Ward Christensen modem 7 protocol file tranmission handler, pt 2
CALLING PARAMETERS:
none.
===========================================================================*/
wctx()
{
int sectnum;
firstsec=TRUE;
totsecs=0;
#ifdef STATLINE
pstat("Awaiting initial NAK");
#else
printf("Awaiting NAK");
#endif
/* get the first char, it must be legal */
while ( ((firstch=readbyte(400))!=TIMEOUT) && (firstch!=WANTCRC)
&& (firstch!=NAK) && (firstch!=CAN) )
printf("%c", firstch); /* let user see it if strange char */
/* CAN = abort */
if (firstch==CAN)
return ERROR;
/* file transmission in CRC mode */
if (firstch==WANTCRC)
Crcflg=TRUE;
/* NAK or WANTCRC rx */
sectnum=1;
/* fill buffer from input file */
while (filbuf(Utility.ubuf, blklen))
{
totsecs += (blklen/128);
if (!Quiet
#ifdef STATLINE
)
pstat("block %3d %2dk", totsecs, totsecs/8 );
#else
&& !View)
printf("\rblock %3d %2dk ", totsecs, totsecs/8 );
#endif
/* send buffered block to modem */
if (wcputsec(Utility.ubuf, sectnum, blklen)==ERROR)
{
return ERROR;
}
/* successful transfer */
else
{
/* View can't be set in xyam, otherwise display transfer */
if (View)
for (cp=Utility.ubuf,wcj=blklen;--wcj>=0;)
putchar(*cp++);
/* next sector(block) */
sectnum++;
}
}
/* finished, close files */
closetx(FALSE);
for (errors=0; ++errors<RETRYMAX; )
{
sendbyte(EOT);
purgeline();
if(readbyte(100) == ACK)
return OK;
}
wcperr("No ACK on EOT\n");
return ERROR;
} /* wctx */
/****************************************************************************
FUNCTION:
wcputsec outputs a Ward Christensen type sector.
Returns sector number encountered or ERROR if valid sector not received,
or CAN CAN received or WCEOT if eot sector.
time is timeout for first char, set to 4 seconds thereafter
*************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
(Caller must do that when he is good and ready to get next sector)
CALLING PARAMETERS:
txbuf:
pointer to buffer to send to modem
sectnum:
number of block to send per WC Xmodem protocol
reclen:
length of block. Must = 128 to be xmodem compatible
===========================================================================*/
wcputsec(txbuf, sectnum, reclen)
char *txbuf;
int sectnum;
int reclen; /* data length of this sector to send */
{
firstch=0; /* part of logic to detect CAN CAN */
for (errors=0; errors <= RETRYMAX; ++errors, ++toterrs)
{
Lastrx = firstch;
/* modified so if block length is <> 128 (default for modem7) STX
will be transmitted */
sendbyte(reclen==KSIZE?STX:SOH);
sendbyte(sectnum);
sendbyte(-sectnum-1);
oldcrc=checksum=0;
/* send block */
for (wcj=reclen,cp=txbuf; --wcj>=0; )
{
sendbyte(*cp);
oldcrc=updcrc(*cp, oldcrc);
checksum += *cp++;
}
/* crc mode */
if (Crcflg)
{
oldcrc=updcrc(0,updcrc(0,oldcrc));
sendbyte(oldcrc>>8);
sendbyte(oldcrc);
}
/* checksum only transfer */
else
sendbyte(checksum);
/* allow abort on ^c */
if(CIREADY && getcty()==CAN)
goto cancan;
purgeline();
/* ignore line noise, esp. braces from 212's */
switch(firstch=readbyte(100))
{
case CAN:
/* CAN CAN - cancel */
if(Lastrx==CAN)
{
cancan:
printf("\nReceiver CANcelled\n");
return ERROR;
}
break;
case ACK|0200:
case ACK:
firstsec=FALSE;
return OK;
case TIMEOUT:
wcperr("Timeout on block ACK\n");
break;
case WANTCRC:
if (firstsec)
Crcflg=TRUE;
case NAK:
wcperr("NAK on block\n");
break;
default:
wcperr(NULL);
printf("Got 0%o for block ACK\n", firstch);
break;
}
for (;;)
{
Lastrx=firstch;
if ((firstch=readbyte(3))==TIMEOUT)
break;
if (firstch==CAN && Lastrx==CAN)
goto cancan;
/* let user see it if strange char */
printf("%c", firstch);
}
}
wcperr("No ACK on block; Abort\n");
return ERROR;
} /* wcputsec */
/****************************************************************************
FUNCTION:
send 10 CAN's to try to get the other end to shut up
CALLING PARAMETERS:
===========================================================================*/
canit()
{
for (wcj=10; --wcj>=0; )
sendbyte(CAN);
} /* canit */
#ifdef DEFBYTL
/****************************************************************************
FUNCTION:
process incoming header for additional file info
CALLING PARAMETERS:
===========================================================================*/
procheader(name)
char *name;
{
char *p;
/* set default parameters */
Bytesleft = DEFBYTL;
Filemode = 0666;
Modtime = 0L;
if (name)
{
p = name + 1 + strlen(name);
/* file coming from Unix type system */
if (*p)
{
/* place additional info into file name string */
sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
printf("%s ", p);
}
}
return OK;
} /* procheader */
#endif